The process of emulating the functionality of a first computer platform (the “target system”) on a second computer platform (the “host system”) so that the host system can execute programs designed for the target system is known as “emulation.” Emulation has commonly been achieved by creating software that interprets and translates programs designed for the target platform into the native-language of a host platform, thus achieving compatibility. More recently, emulation has also been realized through the creation of “virtual machines,” in which the target platform's physical architecture—the design of the hardware itself—is replicated via a virtual model in software.
While both methods can emulate the functionality of the target platform on host systems, they do so with varying degrees of performance. It's not uncommon for an emulator to run programs much slower on the host system than on the target system, depending on the complexity of the target system and executable code relative to the host system. The burden placed on the host system in first interpreting instructions written for an entirely different kind of machine, then executing those instructions within its own architecture, is enormous. Often the host system simply does not have enough power to do the extra work adequately at a speed comparable to the target system.
Conversely, some emulators can operate too quickly on host systems. In some cases, the greatly accelerated instruction execution speed of newer processors means they can execute the instructions required for emulation, plus the instructions of the non-native software, and still outpace the target system running the same software.
Inconsistent emulation performance is also a problem where target and host systems not only require different instruction languages, but also different microprocessor architectures and means of executing instructions. For example, Reduced Instruction Set Computing (RISC) @ processors use one processor cycle to perform an instruction, while Complex Instruction Set Computing (CISC) processors can require ½, 3, 6, even 10 or more processor clock cycles to execute an instruction.
In addition, the explosion in the personal computer industry has led to a near-infinite number of possible configurations of host systems within a given platform, each with vastly different performance characteristics. In a “sealed-box” system, the hardware configuration is locked and consistent from machine to machine. But in open systems, there are a multitude of interfaces, and thousands of different devices that can connect to each, with different effects on the host system.
The task of emulation becomes even more complex when performed on host platforms with higher-level operating systems (like Microsoft® Windows™). Where most older systems were designed to do just one job at a time, some modern operating systems are “multi-tasking.” That means they can perform several operations concurrently by constantly “handing off” control of the processor from one task to another in a manner that is beyond the control of the emulation software. The operating system can interrupt the execution of timing-critical instructions in mid-stream to share processor cycles with another program, in effect “stealing” needed cycles from the emulator.
And finally, the differences between the complex architectures of target platforms and the hosts on which they are emulated may require that the functionality of several co-processors in the target platform be emulated within a single processor on the host system. The host system may perform all functions of the target within a single processor, or assign certain functions to parallel co-processors within its own architecture for greater speed. When the target's processors operate in parallel, an interrupt signal from the CPU is generally required to pause processor operation and to allow the processors to output their results. The host's CPU cannot generate the necessary interrupt for a coprocessor on the host system until those operations are completed, resulting in inefficient emulation and inconsistent timing due to the introduction of unnecessary “wait times” wherein a coprocessor on the host system may be finished with its task, but unable to progress to the next task until an interrupt is received.
This variance may be less noticeable—or even desirable—in programs like word processors and spreadsheets, but becomes all-important when dealing with timing-critical operations like: (1) sound and video playback; (2) processing “streaming” information, where data is delivered to the processor at a constant rate; and (3) games and animations which require screen updates to display motion accurately.
Maintaining timing accuracy is a simple process when writing native code for a computer platform with consistent timing characteristics. The following is an example of rendering an object moving through space at a consistent rate of 60 ft/sec.
A “virtual world” is described in the code, with whatever “real world” physical rules the programmer chooses to include—motion, acceleration, gravity, inertia, etc. Objects can be defined and acted upon within this virtual world, and the results displayed via the monitor to the “real world”. This virtual world's scale, scope and “physical laws” are defined, and the characteristics of an object are described in terms of shape, lighting, color, etc.
The timing of display output and other concurrent processes like sound and disk access are maintained by an “interrupt” signal whose frequency is consistent and determined according to the purpose and timing characteristics of the target platform. For example, if the system has a consistent speed of instruction execution and a known screen-refresh rate (i.e., the rate at which it redraws the information on the monitor) of 60 frames/sec, the instructions that are describing motion as a function of time in the virtual world are linked to the rate at which the system operates and interrupts may be linked to rate at which the image is updated and displayed in the real world. If the object is to move 60 ft/sec, and the system redraws to the monitor at exactly 60 frames/sec, the code instructs the object to “move” one foot per screen refresh/interrupt, so that in one second of real time, the object will appear to have moved 60 feet, as shown in FIG. 1. If the instructions required to prepare the updated image and perform concurrent activities are completed before the interrupt is generated, the results are held in memory until called on, when processing begins on the next set of instructions. If the required instructions cannot be executed in time before the next interrupt is received, the programmer adjusts the code to operate within the limitations of the system.
For the reasons described above, emulation on a host platform in which timing characteristics not only vary from system to system, but are variable within any given system, can result in wildly inconsistent results. (See also discussion below in connection with FIGS. 2 and 3.)
The present invention addresses these issues and provides a method for simulating the timing characteristics of a target platform designed for consistent instruction execution speed by measuring, predicting and dynamically adjusting for timing variability within a host platform, regardless of variations in the timing characteristics of individual host systems, within the limitations and flexibility of the operating environment.